//
//  FileManager+Extension.swift
//  8btc
//
//  Created by Steven Xie on 2018/11/15.
//  Copyright © 2018 Hangzhou Shichuo Information Technology Co, Ltd. All rights reserved.
//

public extension FileManager {
    func fileSizeAtPath(path: String) -> Int {
        do {
            let item = try attributesOfItem(atPath: path)
            return item[FileAttributeKey.size] as! Int
        } catch {
            return 0
        }
    }

    func folderSizeAtPath(path: String) -> Int {
        var size = 0
        do {
            let filese = try subpathsOfDirectory(atPath: path)
            for file in filese {
                size += fileSizeAtPath(path: path + "/" + file)
            }
            return size
        } catch {
            return -1
        }
    }

    func allocatedSizeOfDirectoryAtURL(directoryURL: URL) throws -> UInt64 {
        // We'll sum up content size here:
        var accumulatedSize = UInt64(0)

        // prefetching some properties during traversal will speed up things a bit.
        let prefetchedProperties = [
            URLResourceKey.isRegularFileKey,
            URLResourceKey.fileAllocatedSizeKey,
            URLResourceKey.totalFileAllocatedSizeKey,
        ]

        // The error handler simply signals errors to outside code.
        var errorDidOccur: Error?
        let errorHandler: (URL, Error) -> Bool = { _, error in
            errorDidOccur = error
            return false
        }

        // We have to enumerate all directory contents, including subdirectories.
        let enumerator = self.enumerator(at: directoryURL, includingPropertiesForKeys: prefetchedProperties, options: FileManager.DirectoryEnumerationOptions(), errorHandler: errorHandler)
        precondition(enumerator != nil)

        // Start the traversal:
        for item in enumerator! {
            let contentItemURL = item as! URL

            // Bail out on errors from the errorHandler.
            if errorDidOccur != nil {
                continue
                //                throw error
            }

            let resourceValueForKey: (String) throws -> NSNumber? = { key in
                let set = try contentItemURL.resourceValues(forKeys: [URLResourceKey(key)])
                return set.allValues[URLResourceKey(key)] as? NSNumber
            }

            // Get the type of this item, making sure we only sum up sizes of regular files.
            guard let isRegularFile = try resourceValueForKey(URLResourceKey.isRegularFileKey.rawValue) else {
                preconditionFailure()
            }

            guard isRegularFile.boolValue else {
                continue
            }

            // To get the file's size we first try the most comprehensive value in terms of what the file may use on disk.
            // This includes metadata, compression (on file system level) and block size.
            var fileSize = try resourceValueForKey(URLResourceKey.totalFileAllocatedSizeKey.rawValue)

            // In case the value is unavailable we use the fallback value (excluding meta data and compression)
            // This value should always be available.
            fileSize = try fileSize ?? resourceValueForKey(URLResourceKey.fileAllocatedSizeKey.rawValue)

            guard let size = fileSize else {
                preconditionFailure("huh? NSURLFileAllocatedSizeKey should always return a value")
            }

            // We're good, add up the value.
            accumulatedSize += size.uint64Value
        }

        // Bail out on errors from the errorHandler.
        //        if let error = errorDidOccur { throw error }

        // We finally got it.
        return accumulatedSize
    }
}
